package user

import (
	"context"
	"errors"
	"fmt"
	"time"

	"battle/db"

	"database/sql"

	"github.com/jmoiron/sqlx"
)

// Repository 用户数据仓库接口
type Repository interface {
	// 用户相关操作
	CreateUser(user *User) (int64, error)
	GetUserByID(id int64) (*User, error)
	GetUserByUsername(username string) (*User, error)
	UpdateUserLastLogin(id int64, lastLogin time.Time) error

	// 会话相关操作
	CreateSession(session *Session) error
	GetSessionByID(sessionID string) (*Session, error)
	UpdateSessionLastActive(sessionID string, lastActive time.Time) error
	DeleteSession(sessionID string) error
}

// SQLRepository 基于SQL数据库的用户仓库实现
type SQLRepository struct {
	db *sqlx.DB
}

// NewSQLRepository 创建新的SQL用户仓库
func NewSQLRepository(db *sqlx.DB) Repository {
	return &SQLRepository{db: db}
}

// CreateUser 创建新用户
func (r *SQLRepository) CreateUser(user *User) (int64, error) {
	query := `INSERT INTO users (username, password, email, created_at, last_login) 
              VALUES (:username, :password, :email, :created_at, :last_login)`

	user.CreatedAt = time.Now()
	user.LastLogin = time.Now()

	result, err := r.db.NamedExec(query, user)
	if err != nil {
		return 0, fmt.Errorf("创建用户失败: %w", err)
	}

	id, err := result.LastInsertId()
	if err != nil {
		return 0, fmt.Errorf("获取用户ID失败: %w", err)
	}

	return id, nil
}

// GetUserByID 根据ID获取用户
func (r *SQLRepository) GetUserByID(id int64) (*User, error) {
	query := `SELECT id, username, password, email, created_at, last_login 
              FROM users WHERE id = ?`

	var user User
	err := r.db.Get(&user, query, id)

	if err != nil {
		if errors.Is(err, sql.ErrNoRows) {
			return nil, fmt.Errorf("用户不存在")
		}
		return nil, fmt.Errorf("查询用户失败: %w", err)
	}

	return &user, nil
}

// GetUserByUsername 根据用户名获取用户
func (r *SQLRepository) GetUserByUsername(username string) (*User, error) {
	query := `SELECT id, username, password, email, created_at, last_login 
              FROM users WHERE username = ?`

	var user User
	err := r.db.Get(&user, query, username)

	if err != nil {
		if errors.Is(err, sql.ErrNoRows) {
			return nil, fmt.Errorf("用户不存在")
		}
		return nil, fmt.Errorf("查询用户失败: %w", err)
	}

	return &user, nil
}

// UpdateUserLastLogin 更新用户最后登录时间
func (r *SQLRepository) UpdateUserLastLogin(id int64, lastLogin time.Time) error {
	query := `UPDATE users SET last_login = :last_login WHERE id = :id`

	params := map[string]interface{}{
		"id":         id,
		"last_login": lastLogin,
	}

	_, err := r.db.NamedExec(query, params)
	if err != nil {
		return fmt.Errorf("更新用户登录时间失败: %w", err)
	}

	return nil
}

// CreateSession 创建新会话
func (r *SQLRepository) CreateSession(session *Session) error {
	// 将会话写入Redis
	sessionKey := fmt.Sprintf("session:%s", session.SessionID)
	ctx := context.Background()

	// 使用Redis哈希表存储会话数据
	err := db.RedisClient.HSet(ctx, sessionKey,
		"user_id", session.UserID,
		"virtual_ip", session.VirtualIP,
		"created_at", session.CreatedAt.Format(time.RFC3339),
		"expire_at", session.ExpireAt.Format(time.RFC3339),
		"last_active", session.LastActive.Format(time.RFC3339),
	).Err()
	if err != nil {
		return fmt.Errorf("创建会话失败: %w", err)
	}

	// 设置过期时间
	expiration := session.ExpireAt.Sub(time.Now())
	if expiration > 0 {
		err = db.RedisClient.Expire(ctx, sessionKey, expiration).Err()
		if err != nil {
			return fmt.Errorf("设置会话过期时间失败: %w", err)
		}
	}

	return nil
}

// GetSessionByID 根据ID获取会话
func (r *SQLRepository) GetSessionByID(sessionID string) (*Session, error) {
	sessionKey := fmt.Sprintf("session:%s", sessionID)
	ctx := context.Background()

	// 从Redis获取会话数据
	data, err := db.RedisClient.HGetAll(ctx, sessionKey).Result()
	if err != nil {
		return nil, fmt.Errorf("获取会话失败: %w", err)
	}

	// 检查会话是否存在
	if len(data) == 0 {
		return nil, fmt.Errorf("会话不存在或已过期")
	}

	// 解析会话数据
	userID, err := parseInt64(data["user_id"])
	if err != nil {
		return nil, fmt.Errorf("解析会话数据失败: %w", err)
	}

	createdAt, err := parseTime(data["created_at"])
	if err != nil {
		return nil, fmt.Errorf("解析会话创建时间失败: %w", err)
	}

	expireAt, err := parseTime(data["expire_at"])
	if err != nil {
		return nil, fmt.Errorf("解析会话过期时间失败: %w", err)
	}

	lastActive, err := parseTime(data["last_active"])
	if err != nil {
		return nil, fmt.Errorf("解析会话最后活动时间失败: %w", err)
	}

	session := &Session{
		SessionID:  sessionID,
		UserID:     userID,
		VirtualIP:  data["virtual_ip"],
		CreatedAt:  createdAt,
		ExpireAt:   expireAt,
		LastActive: lastActive,
	}

	return session, nil
}

// UpdateSessionLastActive 更新会话最后活动时间
func (r *SQLRepository) UpdateSessionLastActive(sessionID string, lastActive time.Time) error {
	sessionKey := fmt.Sprintf("session:%s", sessionID)
	ctx := context.Background()

	// 更新最后活动时间
	err := db.RedisClient.HSet(ctx, sessionKey, "last_active", lastActive.Format(time.RFC3339)).Err()
	if err != nil {
		return fmt.Errorf("更新会话最后活动时间失败: %w", err)
	}

	return nil
}

// DeleteSession 删除会话
func (r *SQLRepository) DeleteSession(sessionID string) error {
	sessionKey := fmt.Sprintf("session:%s", sessionID)
	ctx := context.Background()

	// 从Redis删除会话
	err := db.RedisClient.Del(ctx, sessionKey).Err()
	if err != nil {
		return fmt.Errorf("删除会话失败: %w", err)
	}

	return nil
}

// 辅助函数

// parseInt64 将字符串转换为int64
func parseInt64(s string) (int64, error) {
	var i int64
	_, err := fmt.Sscanf(s, "%d", &i)
	return i, err
}

// parseTime 将RFC3339格式的字符串转换为时间
func parseTime(s string) (time.Time, error) {
	return time.Parse(time.RFC3339, s)
}
